<template>
  <div class="ztree-wrapper">
    <input v-if="hasSearch" v-model="keyValue"  placeholder="搜索关键字" type="search">
    <div class="ztree-box">
      <div v-show="noData">未找到对应条目</div>
      <div v-if="zNodes.length == 0">{{ emptyText }}</div>
      <ul :id="treeId" ref="ztree" class="ztree" />
    </div>
  </div>
</template>

<script>

export default {
  name: 'VueTree',
  props:{
    //ref值
    treeId:{
      type:String,
      default:'treeDemo'
    },
    //是否有搜索功能
    hasSearch:{
      type:Boolean,
      default:false
    },
    //空数据时 提示语
    emptyText:{
      type:String,
      default:'暂无数据'
    },
    // 多选是否包含 父节点
    includeParent:{
      type:Boolean,
      default:false
    },
    // 是否是多选
    isCheck:{
      type:Boolean,
      default:false
    },
    //是否全部展开
    openAll:{
      type:Boolean,
      default:false
    },
    //选中状态下的字体样式
    highLightCss:{
      type:Object,
      default(){
        return {'color':'blue','font-weight':'bold'}
      }
    },
    //数据结构
    dataStructure:{
      type:Object,
      default(){
        return {
          idKey: 'id',
          pIdKey: 'pId',
        }
      }
    }
  },
  data() {
    return {
      keyValue: '',
      noData: false,
      treeObj: '',
      nodes: [],
      allNodes: [],
      nodesShow: [],
      zNodes: [],
      setting: {
        data: {
          simpleData: {
            enable: true,
            rootPId: 0,//用于修正根节点父节点数据，即 pIdKey 指定的属性值。
            ...this.dataStructure
          }
        },
        check: {
          enable: false,
          chkStyle:'checkbox',
          chkboxType : { "Y" : "ps", "N" : "ps" },
        },
        view: {
          nameIsHTML: true,
          selectedMulti: false,
          showIcon:false,
          showLine:false,
          fontCss: this.getFont,
        },
        edit: {
          enable: false,
          editNameSelectAll: false
        },
        callback: {
          onClick: this.onClick,
          //用于捕获 checkbox / radio 被勾选 或 取消勾选的事件回调函数
          onCheck: this.onCheck
        }
      }
    }
  },
  watch: {
    keyValue(newV) {
      console.log('筛选发生变化',newV)
      if(this.zNodes.length == 0){
        return false
      }
      this.searchFun(newV, null, true)
    },
    'setting.view.showLine'(val){
      //配置发生变化  初始化tree组件
      console.log('配置发生变化  初始化tree组件',val)
      this.initzTree()
    },
    'setting.view.showIcon'(val){
      //配置发生变化  初始化tree组件
      console.log('配置发生变化  初始化tree组件',val)
      this.initzTree()
    },
    'setting.check.enable'(val){
      //配置发生变化  初始化tree组件
      console.log('配置发生变化  初始化tree组件',val)
      this.initzTree()
    }
  },
  created() {
    this.setting.check.enable = this.isCheck
    this.initzTree()
  },
  methods: {
    //设置 setting 值
    setData(data) {
      console.log('切换数据源了 ')
      this.zNodes = data
      this.initzTree()
    },
    initzTree() {
      this.treeObj = $.fn.zTree.init($('#' + this.treeId), this.setting, this.zNodes)
      var nodes = this.treeObj.getNodes()
      this.allNodes = this.queryFun(nodes)
      // 展开全部
      if(this.openAll){
        this.treeObj.expandAll(true)
      }else {
        // 未设置全部展开  默认展开到二级节点
        var rootNodes = this.treeObj.getNodesByParam('level', '1')
        rootNodes.forEach(node => {
          this.treeObj.expandNode(node, true)
        })
      }
    },
    queryFun(node) {
      for (var i in node) {
        this.nodes.push(node[i])
        if (node[i].children) {
          this.queryFun(node[i].children)
        }
      }
      return this.nodes
    },
    searchFun(val, isHighLight, isExpand) {
      var key = val.replace(/(^\s*)|(\s*$)/g, '')
      this.nodesShow = []
      isHighLight = isHighLight !== false
      isExpand = !!isExpand
      this.filterzTree(key, this.allNodes, isExpand, isHighLight)
      if (this.keyValue === '') {
        this.noData = false
      } else {
        if (this.nodesShow.length === 0) {
          this.noData = true
        } else {
          this.noData = false
        }
      }
      this.showNodesFun(this.nodesShow, key)
    },
    filterzTree(key, nodes, isExpand, isHighLight) {
      var metaChar = '[\\[\\]\\\\\^\\$\\.\\|\\?\\*\\+\\(\\)]'
      var rexMeta = new RegExp(metaChar, 'gi')
      var nameKey = this.treeObj.setting.data.key.name
      for (var i = 0; i < nodes.length; i++) {
        if (nodes[i] && nodes[i].oldname && nodes[i].oldname.length > 0) {
          nodes[i][nameKey] = nodes[i].oldname
        }
        this.treeObj.updateNode(nodes[i])
        if (key === '') {
          this.initzTree()
          break
        } else {
          if (nodes[i][nameKey] && nodes[i][nameKey].toLowerCase().indexOf(key.toLowerCase()) !== -1) {
            if (isHighLight) {
              var newKeywords = key.replace(rexMeta, (matchStr) => {
                return '//' + matchStr
              })
              nodes[i].oldname = nodes[i][nameKey]
              var rexGlobal = new RegExp(newKeywords, 'gi')
              nodes[i][nameKey] = nodes[i].oldname.replace(rexGlobal, (originalText) => {
                var highLightText =
                    '<span style="color: whitesmoke;background-color: darkred;">' +
                    originalText +
                    '</span>'
                return highLightText
              })
              this.treeObj.updateNode(nodes[i])
            }
            this.treeObj.showNode(nodes[i])
            this.nodesShow.push(nodes[i])
          } else {
            this.treeObj.hideNode(nodes[i])
          }
        }
      }
    },
    showNodesFun(nodesShow, key) {
      if (key.length > 0) {
        nodesShow.forEach(node => {
          var pathOfOne = node.getPath()
          if (pathOfOne && pathOfOne.length > 0) {
            for (var i = 0; i < pathOfOne.length - 1; i++) {
              this.treeObj.showNode(pathOfOne[i])
              this.treeObj.expandNode(pathOfOne[i], true)
            }
          }
        })
      } else {
        var rootNodes = this.treeObj.getNodesByParam('level', '0')
        rootNodes.forEach(node => {
          this.treeObj.expandNode(node, true)
        })
      }
    },
    //用于捕获节点被点击的事件回调函数
    onClick(e,treeId, treeNode) {
      console.log('单机选项',e,treeId, treeNode)
      //节节点上是否显示 checkbox / radio  并且 chkStyle == checkbox 才可以点击折叠或打开
      if(this.setting.check.enable&&this.setting.check.chkStyle == 'checkbox'){
        var zTree = $.fn.zTree.getZTreeObj(this.treeId);
        zTree.expandNode(treeNode);
      }else {
        //所有节点恢复初始化样式
        this.treeObj.getNodesByFilter((node)=>{
          return node.highlight
        }).forEach((item)=>{
          item.highlight = false;
          console.log('之前选中的',item)
          this.treeObj.updateNode(item);
        })
        // 获取当前被勾选的节点集合
        var treeObj = $.fn.zTree.getZTreeObj(this.treeId);
        var nodes = treeObj.getSelectedNodes();
        console.log('获取当前点击的节点',nodes)
        nodes[0].highlight = true;
        this.treeObj.updateNode(nodes[0]);
        this.$emit('nodeClick',nodes[0])
      }

    },
    //用于捕获 checkbox / radio 被勾选 或 取消勾选的事件回调函数
    onCheck(e,treeId, treeNode){
      console.log('勾选 或 取消勾选的事件回调函数',e,treeId, treeNode)
      var treeObj = $.fn.zTree.getZTreeObj(this.treeId);
      var halfCheck = treeObj.getNodes()[0].getCheckStatus();
      console.log('获取第一个根节点的半选状态',halfCheck)
      var nodes = treeObj.getCheckedNodes(true);
      console.log('获取节点为选中的状态状态',nodes)
      //判断是否包含父节点 包含回传父节点 反之亦然
      var lables,values;
      if(this.includeParent){
        lables = nodes.map((item)=>{
          return item.name
        })
        values = nodes.map((item)=>{
          return item.id
        })
      }else {
        lables = nodes.filter((item)=>{
          return !item.children
        }).map((item)=>{
          return item.name
        })
        values = nodes.filter((item)=>{
          return !item.children
        }).map((item)=>{
          return item.name
        })
      }

      //把数据解析成出来
      /*
      * @nodes
      * @lables
      * @values
      * */
      this.$emit('checkChange',{
        lables,
        values
      })
    },
    //数据回显
    dataEcho(val){
      //数据回显
      console.log('数据回显 值 =',val)
      if(!this.isCheck){
        let nodeList = this.treeObj.getNodesByParam('name', val);
        console.log('符合的数据 =',nodeList)
        for( var i=0, l=nodeList.length; i<l; i++ )
        {
          nodeList[i].highlight = true;
          nodeList[i].hiddenNodes = false;
          this.treeObj.updateNode(nodeList[i]);
        }
      }else {
        console.log('多选数据回显',val)
        let selData = val.split(',')
        console.log('多选的数据=',selData)
        this.treeObj.getNodesByFilter((node)=>{
          return val.indexOf(node.name) > -1
        }).forEach((item)=>{
          item.checked = true;
          this.treeObj.updateNode(item);
        })
      }

    },
    //改变 选中状态的 字体 颜色
    getFont(treeId, node){
      return node.highlight ? this.highLightCss : {'color':'','font-weight':''};
    }
  }
}
</script>

<style>
* {
  padding: 0;
  margin: 0;
}

#app {
  width: 100vw;
  height: 100vh;
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  overflow: hidden;
}

.ztree-wrapper {
  height: 100%;
  width: 100%;
  overflow: hidden;
  padding: 6px;
}

.ztree-box {
  width: 100%;
  height: 100%;
  padding: 10px;
  box-sizing: border-box;
  overflow-x: hidden;
  overflow-y: auto;
}
/*-------------------------------------
zTree Style

version:    3.4
author:     Hunter.z
email:      hunter.z@263.net
website:    http://code.google.com/p/jquerytree/

-------------------------------------*/

.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}
.ztree {margin:0; padding:5px; color:#333}
.ztree li{padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0}
.ztree li ul{ margin:0; padding:0 0 0 18px}
.ztree li ul.line{ background:url('../css/metroStyle/img/line_conn.png') 0 0 repeat-y;}

.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block}
.ztree li a:hover {text-decoration:underline}
.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;padding: 0 4px;}
.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;}
.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid;
  opacity:0.8; filter:alpha(opacity=80)}
.ztree li a.tmpTargetNode_prev {}
.ztree li a.tmpTargetNode_next {}
.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;
  font-size:12px; border:1px #585956 solid; *border:0px}
.ztree li span {line-height:21px; margin-right:2px}
.ztree li span.button {line-height:0; margin:0; padding: 0; width:14px; height:14px; display: inline-block; vertical-align:middle;
  border:0 none; cursor: pointer;outline:none;
  background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
  background-image:url("../css/metroStyle/img/metro2.png");margin-right: 10px }

.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto}
.ztree li span.button.chk.checkbox_false_full {background-position: 0px 0px;}
.ztree li span.button.chk.checkbox_false_full_focus {background-position: 0px -14px;}
.ztree li span.button.chk.checkbox_false_part {background-position: 0px -28px;}
.ztree li span.button.chk.checkbox_false_part_focus {background-position: 0px -42px;}
.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;}
.ztree li span.button.chk.checkbox_true_full {background-position: -14px 0px;}
.ztree li span.button.chk.checkbox_true_full_focus {background-position: -14px -14px;}
.ztree li span.button.chk.checkbox_true_part {background-position: -14px -42px;}
.ztree li span.button.chk.checkbox_true_part_focus {background-position: -14px -28px;}
.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;}
.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;}
.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;}
.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;}
.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;}
.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;}
.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;}
.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;}
.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;}
.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;}
.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;}

.ztree li span.button.switch {width:21px; height:21px}
.ztree li span.button.root_open{background-position:-89px -74px}
.ztree li span.button.root_close{background-position:-69px -72px}
.ztree li span.button.roots_open{background-position: -105px 0;}
.ztree li span.button.roots_close{background-position: -126px 0;}
.ztree li span.button.center_open{background-position: -89px -72px;}
.ztree li span.button.center_close{background-position: -69px -72px}
.ztree li span.button.bottom_open{background-position: -89px -72px;}
.ztree li span.button.bottom_close{background-position: -69px -72px;}
.ztree li span.button.noline_open{background-position: -88px -71px;}
.ztree li span.button.noline_close{background-position: -71px -71px;}
.ztree li span.button.root_docu{ background:none;}
.ztree li span.button.roots_docu{background:none;}
.ztree li span.button.center_docu{background:none;}
.ztree li span.button.bottom_docu{background:none;}
.ztree li span.button.noline_docu{ background:none;}

.ztree li span.button.ico_open{margin-right:2px; background-position: -111px -17px; vertical-align:sub; *vertical-align:middle}
.ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -127px -1px; vertical-align:sub; *vertical-align:middle}
.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:sub; *vertical-align:middle}
.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:sub; *vertical-align:middle}
.ztree li span.button.edit:hover {
  background-position: -168px -21px;
}
.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.remove:hover {
  background-position: -168px -42px;
}
.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle}
.ztree li span.button.add:hover {
  background-position: -168px 0;
}
.ztree li span.button.ico_loading{margin-right:2px; background:url('../css/metroStyle/img/loading.gif') no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}

ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}

span.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;
  background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
  background-position:-168px -84px; background-image:url("../css/metroStyle/img/metro2.png"); }

ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}
.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}

</style>

